package com.wfh.yudada.scroing;

import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.wfh.yudada.model.dto.question.QuestionAnswerDTO;
import com.wfh.yudada.model.dto.question.QuestionContentDTO;
import com.wfh.yudada.model.entity.App;
import com.wfh.yudada.model.entity.Question;
import com.wfh.yudada.model.entity.ScoringResult;
import com.wfh.yudada.model.entity.UserAnswer;
import com.wfh.yudada.model.vo.QuestionVO;
import com.wfh.yudada.service.QuestionService;
import com.wfh.yudada.service.ScoringResultService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author FengHuan Wang
 * @Date 2025/5/23 12:27
 * @Version 1.0
 */
@ScoringStrategyConfig(appType = 1, scoringStrategy = 1)
public class CunstomTestScoringStrategy implements ScoringStrategy {

    @Resource
    private QuestionService questionService;

    @Resource
    private ScoringResultService scoringResultService;

    @Resource
    private RedissonClient redissonClient;

    private static final String AI_ANSWER_LOCK = "AI_ANSWER_LOCK";

    /**
     * 本地缓存
     */
    private final Cache<String, String> answerCacheMap =
            Caffeine.newBuilder().initialCapacity(1024)
            // 缓存5分钟后删除啊
                    .expireAfterAccess(5L, TimeUnit.MINUTES)
                    .build();



    private static final String AI_TEST_SCORING_SYSTEM_MESSAGE = "你是一位严谨的判题专家，我会给你如下信息：\n" +
            "```\n" +
            "应用名称，\n" +
            "【【【应用描述】】】，\n" +
            "题目和用户回答的列表：格式为 [{\"title\": \"题目\",\"answer\": \"用户回答\"}]\n" +
            "```\n" +
            "\n" +
            "请你根据上述信息，按照以下步骤来对用户进行评价：\n" +
            "1. 要求：需要给出一个明确的评价结果，包括评价名称（尽量简短）和评价描述（尽量详细，大于 200 字）\n" +
            "2. 严格按照下面的 json 格式输出评价名称和评价描述\n" +
            "```\n" +
            "{\"resultName\": \"评价名称\", \"resultDesc\": \"评价描述\"}\n" +
            "```\n" +
            "3. 返回格式必须为 JSON 对象";

    private String getAiTestScoringUserMessage(App app, List<QuestionContentDTO> questionContentDTOList, List<String> choices) {
        StringBuilder userMessage = new StringBuilder();
        userMessage.append(AI_TEST_SCORING_SYSTEM_MESSAGE);
        userMessage.append(app.getAppName()).append("\n");
        userMessage.append(app.getAppDesc()).append("\n");
        List<QuestionAnswerDTO> questionAnswerDTOList = new ArrayList<>();
        for (int i = 0; i < questionContentDTOList.size(); i++) {
            QuestionAnswerDTO questionAnswerDTO = new QuestionAnswerDTO();
            questionAnswerDTO.setTitle(questionContentDTOList.get(i).getTitle());
            questionAnswerDTO.setUserAnswer(choices.get(i));
            questionAnswerDTOList.add(questionAnswerDTO);
        }
        userMessage.append(JSONUtil.toJsonStr(questionAnswerDTOList));
        return userMessage.toString();
    }


    @Override
    public UserAnswer doScore(List<String> choices, App app) throws Exception {
        Long appId = app.getId();
        String jsonStr = JSONUtil.toJsonStr(choices);
        String cacheKey = buildCacheKey(appId, jsonStr);
        String answerCacheMapIfPresent = answerCacheMap.getIfPresent(cacheKey);
        if (answerCacheMapIfPresent != null) {
            UserAnswer userAnswer = JSONUtil.toBean(answerCacheMapIfPresent, UserAnswer.class);
            userAnswer.setAppId(app.getId());
            userAnswer.setAppType(app.getAppType());
            userAnswer.setScoringStrategy(app.getScoringStrategy());
            userAnswer.setChoices(JSONUtil.toJsonStr(choices));
            return userAnswer;
        }
        // 定义锁
        RLock lock = redissonClient.getLock(AI_ANSWER_LOCK + cacheKey);
        UserAnswer userAnswer = null;

        try {
            // 竞争锁
            boolean res = lock.tryLock(3, 15, TimeUnit.SECONDS);
            if (!res){
                throw new RuntimeException("获取锁失败");
            }
            // 根据id查询题目的结果和题目的结果信息
            Question question = questionService.getOne(Wrappers.lambdaQuery(Question.class)
                    .eq(Question::getAppId, app.getId()));
            List<ScoringResult> scoringResultList = scoringResultService
                    .list(Wrappers.lambdaQuery(ScoringResult.class)
                            .eq(ScoringResult::getAppId, app.getId()));
            // 统计用户每个选项的个数
            int totalScore = 0;
            QuestionVO questionVO = new QuestionVO();
            List<QuestionContentDTO> questionContent = questionVO.getQuestionContent();

            // 封装prompt
            String prompt = getAiTestScoringUserMessage(app, questionContent, choices);
            // ai生成
            /*String response = aiManager.doAiRequest(false, prompt, 1.0f);*/
            // 结果处理
            // 解析结果
/*        int start = response.indexOf("{");
        int end = response.lastIndexOf("}");
        String result = response.substring(start, end + 1);*/
            String result = "{\"resultName\":\"优秀\",\"resultDesc\":\"用户回答了所有题目，并且回答正确，非常优秀\"}";
            // todo 缓存value
            answerCacheMap.put(cacheKey, result);
            userAnswer = JSONUtil.toBean(result, UserAnswer.class);
            // 构造返回值，填充返回对象的信息
            userAnswer.setAppId(app.getId());
            userAnswer.setAppType(app.getAppType());
            userAnswer.setScoringStrategy(app.getScoringStrategy());
            userAnswer.setChoices(JSONUtil.toJsonStr(choices));
            userAnswer.setResultScore(totalScore);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (lock != null && lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }
        }
        return userAnswer;
    }

    /**
     * 构建缓存key
     * @param appId
     * @param choices
     * @return
     */
    private String buildCacheKey(Long appId, String choices) {
        return DigestUtil.md5Hex(appId + ":" + choices);
    }
}
